import platform, os, filetype
from enum import Enum
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.chrome.webdriver import WebDriver as ChromeDriver
from selenium.webdriver.chrome.options import Options as ChromeOptions
from selenium.webdriver.firefox.options import Options as FirefoxOptions
from selenium.webdriver.firefox.service import Service as FirefoxService
from selenium.webdriver.firefox.webdriver import WebDriver as FirefoxDriver
from selenium.webdriver.remote.webdriver import WebDriver as RemoteDriver
from support.files.archive import ArchiveFileHelper
from support.network.nethelper import NetHelper
from support.utils.toolkit import Log

class BrowserHelper:
    ROOTDIR = os.path.join(os.getcwd(), 'driver')
    URL_MAP = Enum('URL', {
    'chrome' : 'https://repo.huaweicloud.com/chromedriver/',
    'gecko' : 'https://mirrors.huaweicloud.com/geckodriver/',
    'opera' : 'https://mirrors.huaweicloud.com/operadriver/'
    })
    
    OS_MAP = Enum('OS', {
        'windows' : 'win',
        'mac' : 'mac',
        'linux' : 'linux'
    })
    
    TYPE_MAP = Enum('TYPE', {
        'chrome' : 'chromedriver',
        'gecko' : 'geckodriver',
        'opera' : 'operadriver'
    })
    
    MACHINE_MAP = Enum('MACHINE', {
        'chrome-arm64': '-arm64',
        'chrome-aarch64':'-arm64',
        'gecko-arm64':'-aarch64',
        'gecko-aarch64':'-aarch64',
        'x86' : '32',
        'x86_x86' : '32',
        'x86_64' : '64',
        'amd64' : '64',
    })
    
    ARM_MACHINE_MAP = {'arm', 'arm32', 'arm64', 'aarch', 'aarch64'}
    
    def __init__(self):
        uname_result = platform.uname()
        self.os = uname_result.system.lower()
        self.machine = uname_result.machine.lower()
        self.nethelper = NetHelper()
        self.archiver = ArchiveFileHelper()
        self.driverinfo = {}
    
    def __autoCreateDriverDirs__():
        for type in BrowserHelper.TYPE_MAP:
            path = os.path.join(BrowserHelper.ROOTDIR, type.name)
            os.makedirs(path, exist_ok=True)
    
    def __translateOS__(self, target):
        self.driverinfo['os'] = BrowserHelper.OS_MAP[self.os].value
        if(self.os == BrowserHelper.OS_MAP.mac.name and target == BrowserHelper.TYPE_MAP.gecko.name):
            self.driverinfo['os'] = 'macos'

    def __translateMachine__(self, target):
        if(self.machine in BrowserHelper.ARM_MACHINE_MAP):
            self.driverinfo['machine'] = targe + '-' + self.machine 
        self.driverinfo['machine'] = BrowserHelper.MACHINE_MAP[self.machine].value
        

    def __getSuffix__(self, target):
        suffix = ".zip"
        if(self.os != BrowserHelper.OS_MAP.windows.value and target == BrowserHelper.TYPE_MAP.gecko.name):
            suffix = ".tar.gz"
        return suffix        
        

    def __getDriverName__(self, target, version):
        self.__translateOS__(target)
        self.__translateMachine__(target)
        name = BrowserHelper.TYPE_MAP[target].value + "-"
        if(target == BrowserHelper.TYPE_MAP.gecko.name):
            name += version + "-"
        name += self.driverinfo['os'] + self.driverinfo['machine']
        name += self.__getSuffix__(target)
        if(target == BrowserHelper.TYPE_MAP.opera.name):
            name = name.replace('-', '_')
        return name
        

    def __getDriverUrl__(self, target, version):
        return BrowserHelper.URL_MAP[target].value + version + '/' +self.__getDriverName__(target, version)

    def __checkLocalDriver__(self, driverPath):
        correctDriverPath = None
        if(os.path.exists(driverPath)):
            for root, dirs, files in os.walk(driverPath):
                for file in files:
                    result = filetype.guess(os.path.join(root, file))
                    if(self.os == BrowserHelper.OS_MAP.windows.name and result.extension == 'exe'):
                        correctDriverPath = os.path.join(root, file)
                    elif(self.os != BrowserHelper.OS_MAP.windows.name and result.extension == 'elf'):
                        correctDriverPath = os.path.join(root, file)
                    if(correctDriverPath):
                        break
                if(correctDriverPath):
                    break
        return correctDriverPath
    
    def autoGetDriver(self, target, version):
        driverPath = os.path.join(BrowserHelper.ROOTDIR, target, version)
        driverUri = self.__checkLocalDriver__(driverPath)
        if(not driverUri):
            Log.i("There( {} ) is no expected driver".format(driverPath))
            driverUri = self.__getDriverUrl__(target, version)
            savePath = self.nethelper.download(driverUri)
            if(savePath):
                Log.i(f"unzip driver archive( {savePath} )")
                self.archiver.unCompress(savePath, driverPath)
                driverUri = self.__checkLocalDriver__(driverPath)
            else:
                driverUri = None
        Log.i(f"finally the driver file is {driverUri}")
        return driverUri

    def chrome(*, host=None, binpath=None, driveruri=None):
        options = ChromeOptions()
        options.add_argument("--headless")
        options.add_argument("--disable-gpu")
        browser = None
        if(host):
            browser = RemoteDriver(command_executor=host, options=options)
        elif(driveruri):
            options.binary_location = binpath
            service = ChromeService(executable_path = driveruri)
            browser = ChromeDriver(service=service, options=options)
        return browser
    
    def firefox(*, host=None, binpath=None, driveruri=None):
        options = FirefoxOptions()
        options.add_argument("--headless")
        browser = None
        if(host):
            browser = RemoteDriver(command_executor=host, options=options)
        elif(driveruri):
            options.binary_location = binpath
            service = FirefoxService(executable_path = driveruri)
            browser = FirefoxDriver(service=service, options=options)
        return browser
    
    def remoteBrowser(type, *, host=None):
        remote = None
        type = BrowserHelper.TYPE_MAP[type]
        if(type == BrowserHelper.TYPE_MAP.gecko):
            remote = BrowserHelper.firefox(host=host)
        elif(type == BrowserHelper.TYPE_MAP.chrome):
            remote = BrowserHelper.chrome(host=host)
        else:
            remote = RemoteDriver(command_executor=host)
        return remote
    
    def localBrowser(typename, binpath, *, uri):
        localbrowser = None
        BrowserHelper.__autoCreateDriverDirs__()
        type = BrowserHelper.TYPE_MAP[typename]
        if(type == BrowserHelper.TYPE_MAP.gecko):
            localbrowser = BrowserHelper.firefox(binpath=binpath, driveruri=uri)
        elif(type == BrowserHelper.TYPE_MAP.chrome):
            localbrowser = BrowserHelper.chrome(binpath=binpath, driveruri=uri)
        return localbrowser
